package com.ibeeking.found.upms.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ibeeking.found.upms.b.rest.service.*;
import com.ibeeking.found.upms.service.common.bo.*;
import com.ibeeking.found.common.constants.GlobalConstant;
import com.ibeeking.found.common.entity.CurrentUser;
import com.ibeeking.found.common.enums.FrontendTypeEnum;
import com.ibeeking.found.upms.api.common.dto.PermissionDTO;
import com.ibeeking.found.upms.api.common.param.PermissionParam;
import com.ibeeking.found.upms.api.feign.UpmsGClient;

import com.ibeeking.found.upms.service.common.constants.RedisKeyConstant;
import com.ibeeking.found.upms.service.common.dos.TenantPermissionDO;
import com.ibeeking.found.upms.service.common.dos.TenantUserPermissionFavorityDO;
import com.ibeeking.found.upms.service.common.param.UserPermissionParam;
import com.ibeeking.found.upms.service.common.vo.CurrentPermissionVO;
import com.ibeeking.found.upms.service.common.vo.PermissionTreeVO;
import com.ibeeking.found.upms.service.mapper.TenantPermissionMapper;
import com.ibeeking.found.upms.service.mapper.TenantUserPermissionFavorityMapper;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.redis.utils.RedisUtils;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.TreeFastUtils;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName TenantPermissionServiceImpl
 * @Description 权限实现类
 * @Author ibeeking
 * @Date 2021-01-04 15:40
 **/
@Service
public class TenantPermissionServiceImpl extends ServiceImpl<TenantPermissionMapper, TenantPermissionDO> implements ITenantPermissionService {

    @Resource
    private TenantPermissionMapper tenantPermissionMapper;
    @Resource
    private TenantUserPermissionFavorityMapper tenantUserPermissionFavorityMapper;
    @Resource
    private IShopPermissionService shopPermissionServiceImpl;
    @Resource
    private ICsPermissionService csPermissionServiceImpl;
    @Resource
    private ICpPermissionService cpPermissionServiceImpl;
    @Resource
    private ITenantRoleService roleServiceImpl;
    @Resource
    private ITenantUserRoleService userRoleServiceImpl;
    @Resource
    private ITenantRolePermissionService rolePermissionServiceImpl;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private UpmsGClient upmsGClient;

    @Override
    public List<CurrentPermissionVO> queryEffectiveList(CurrentUser currentUser, String jti) {
        List<CurrentPermissionVO> result;
        //1 从缓存中查询
        //从缓存中查询用户权限
        Object o = redisUtils.get(RedisKeyConstant.MODULE_B + RedisKeyConstant.USER_PERMISSION + currentUser.getTenantId() + currentUser.getId() + ":" + jti);
        if (null != o) {
            result = JsonUtils.jsonToList(o, CurrentPermissionVO.class);
        } else {

            //3 根据当前登录用户获取当前角色
            List<TenantUserRoleBO> tenantUserRoleBos = userRoleServiceImpl.queryUserRoleByUserId(currentUser.getId());
            if (Collections3.isEmpty(tenantUserRoleBos)) {
                return Collections3.emptyList();
            }
            Long administratorId = roleServiceImpl.selectAdministratorId();
            boolean administrator = currentUser.getRoleIds().contains(administratorId);
            //查询所有菜单
            List<TenantPermissionBO> tenantPermissionBos = getBean().queryAll();
            if (Collections3.isEmpty(tenantPermissionBos)) {
                return Collections3.emptyList();
            }
            result = JsonUtils.jsonToList(tenantPermissionBos, CurrentPermissionVO.class);
            if (!administrator) {
                //4 根据角色查询权限
                List<TenantRolePermissionBO> tenantRolePermissionBos = rolePermissionServiceImpl.queryRolePermissionByRoleIds(currentUser.getRoleIds());
                if (Collections3.isEmpty(tenantRolePermissionBos)) {
                    return Collections3.emptyList();
                }
                List<Long> currentIds = tenantRolePermissionBos.parallelStream().map(TenantRolePermissionBO::getPermissionId).collect(Collectors.toList());
                //5 根据权限查询所有上级权限
                List<Long> resultIds = new ArrayList<>();
                TreeFastUtils.selectLongPidByCid(resultIds, result, currentIds);
                resultIds.addAll(currentIds);
                result = result.stream().filter(currentPermissionVO -> resultIds.contains(currentPermissionVO.getId())).collect(Collectors.toList());
            }

            if (!Collections3.isEmpty(result)) {
                //7 存入缓存
                redisUtils.set(RedisKeyConstant.MODULE_B + RedisKeyConstant.USER_PERMISSION + currentUser.getTenantId() + currentUser.getId() + ":" + jti, result, RedisKeyConstant.HALF_DAY);
            }
        }
        //8 转换数据格式并返回
        return result;
    }
    @Override
    public List<TenantUserFavorityBO> queryUserPermissionFavorityByUserId(Long userId) {
        if(userId == null) return Collections3.emptyList();
        List<TenantUserPermissionFavorityDO> tenantUserPermissionFavorityDOS = tenantUserPermissionFavorityMapper.queryPermissionFavorityByUserIds(userId);
        if(Collections3.isEmpty(tenantUserPermissionFavorityDOS)) return Collections3.emptyList();
        return JsonUtils.jsonToList(tenantUserPermissionFavorityDOS, TenantUserFavorityBO.class);
    }

    @Override
    public List<TenantPermissionBO> queryUserPermissionFavorityList(CurrentUser currentUser) {
        Long userId = currentUser.getId();
        if(userId == null) return Collections3.emptyList();
        List<TenantUserPermissionFavorityDO> tenantUserPermissionFavorityDOS = tenantUserPermissionFavorityMapper.queryPermissionFavorityByUserIds(userId);
        if(Collections3.isEmpty(tenantUserPermissionFavorityDOS)) return Collections3.emptyList();
        List<Long> haveIds = tenantUserPermissionFavorityDOS.stream().map(TenantUserPermissionFavorityDO::getPermissionId).collect(Collectors.toList());

        ResponseResult<List<PermissionDTO>> responseResult = upmsGClient.queryListByIds(haveIds);
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            return Collections3.emptyList();
        }
        List<PermissionTreeVO> permissionTreeVos = JsonUtils.jsonToList(responseResult.getData(), PermissionTreeVO.class);

        return JsonUtils.jsonToList(permissionTreeVos, TenantPermissionBO.class);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean addAndUpdateUserPermissionFavority(CurrentUser currentUser, UserPermissionParam param) {
        Long userId = currentUser.getId();
        if(userId == null ) return true;
        if (null == param.getPermissionIds() || 0 == param.getPermissionIds().length) {
            return true;
        }
        tenantUserPermissionFavorityMapper.delete(new LambdaQueryWrapper<TenantUserPermissionFavorityDO>().eq(TenantUserPermissionFavorityDO::getUserId,userId));
        List<Long> paramIds = Arrays.asList(param.getPermissionIds());
        List<TenantUserPermissionFavorityDO> saves = new ArrayList<>();
        paramIds.stream().forEach(key -> {
            TenantUserPermissionFavorityDO tenantUserPermissionFavorityDO = new TenantUserPermissionFavorityDO();
            tenantUserPermissionFavorityDO.setId(IdGenerator.getId());
            tenantUserPermissionFavorityDO.setUserId(userId);
            tenantUserPermissionFavorityDO.setPermissionId(key);
            saves.add(tenantUserPermissionFavorityDO);
        });
        return tenantUserPermissionFavorityMapper.insertBatchSomeColumn(saves) >0;
    }

    @Override
    public List<TenantPermissionBO> queryAll() {
        List<TenantPermissionDO> tenantPermissionDos = tenantPermissionMapper.selectList(Wrappers.emptyWrapper());
        if (Collections3.isEmpty(tenantPermissionDos)) {
            return Collections3.emptyList();
        }
        ResponseResult<List<PermissionDTO>> responseResult = upmsGClient.queryAllList(Arrays.asList(FrontendTypeEnum.TENANT.getCode()));
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            return Collections3.emptyList();
        }
        List<PermissionTreeVO> permissionTreeVos = JsonUtils.jsonToList(responseResult.getData(), PermissionTreeVO.class);

        List<Long> haveIds = tenantPermissionDos.stream().map(TenantPermissionDO::getId).collect(Collectors.toList());
        List<Long> resultIds = new ArrayList<>();
        TreeFastUtils.selectLongPidByCid(resultIds, permissionTreeVos, haveIds);
        resultIds.addAll(haveIds);
        List<PermissionTreeVO> collect = permissionTreeVos.stream().filter(s -> resultIds.contains(s.getId())).collect(Collectors.toList());
        return JsonUtils.jsonToList(collect, TenantPermissionBO.class);
    }

    @Override
    public List<CurrentPermissionVO> menus(String module) {
        List<CurrentPermissionVO> result = null;
        if (FrontendTypeEnum.SHOP.getCode().equalsIgnoreCase(module)) {
            List<ShopPermissionBO> shopPermissionBos = shopPermissionServiceImpl.queryEffective();
            result = JsonUtils.jsonToList(shopPermissionBos, CurrentPermissionVO.class);
        } else if (FrontendTypeEnum.TENANT.getCode().equalsIgnoreCase(module)) {
            List<TenantPermissionBO> tenantPermissionBos = getBean().queryAll();
            result = JsonUtils.jsonToList(tenantPermissionBos, CurrentPermissionVO.class);
        } else if (FrontendTypeEnum.CUSTOMER_SERVICE.name().equalsIgnoreCase(module)) {
            List<CsPermissionBO> csPermissionBos = csPermissionServiceImpl.queryEffective();
            result = JsonUtils.jsonToList(csPermissionBos, CurrentPermissionVO.class);
        }  else if (FrontendTypeEnum.CP.name().equalsIgnoreCase(module)) {
            List<CpPermissionBO> cpPermissionBos = cpPermissionServiceImpl.queryEffective();
            result = JsonUtils.jsonToList(cpPermissionBos, CurrentPermissionVO.class);
        } else {
            result = Collections3.emptyList();
        }
        return TreeFastUtils.listToTree(result, GlobalConstant.PARENT_ID);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Boolean configurePermission(List<PermissionParam> params) {
        if (Collections3.isEmpty(params)) {
            return true;
        }
        Boolean flag = false;
        Map<String, List<PermissionParam>> group = params.parallelStream().collect(Collectors.groupingBy(PermissionParam::getModule));
        for (Map.Entry<String, List<PermissionParam>> map : group.entrySet()) {
            String module = map.getKey();
            if (FrontendTypeEnum.SHOP.getCode().equals(module)) {
                flag = shopPermissionServiceImpl.configurePermission(params);
            } else if (FrontendTypeEnum.TENANT.getCode().equals(module)) {
                tenantPermissionMapper.delete(Wrappers.emptyWrapper());
                List<TenantPermissionDO> tenantPermissionDos = JsonUtils.jsonToList(params, TenantPermissionDO.class);
                tenantPermissionDos.stream().forEach(d->{
                    d.setCreateTime(LocalDateTime.now());
                });
                flag = tenantPermissionMapper.insertBatchSomeColumn(tenantPermissionDos) > 0;
            } else if (FrontendTypeEnum.CUSTOMER_SERVICE.getCode().equals(module)) {
                flag = csPermissionServiceImpl.configurePermission(params);
            }  else if (FrontendTypeEnum.CP.getCode().equals(module)) {
                flag = cpPermissionServiceImpl.configurePermission(params);
            }  else {
                flag = false;
            }
            if (!flag) {
                throw new BusinessException("租户菜单配置异常");
            }
        }
        return flag;
    }

    @Override
    public List<Long> queryAllByModule(String module) {
        if (FrontendTypeEnum.SHOP.getCode().equals(module)) {
            List<ShopPermissionBO> shopPermissionBos = shopPermissionServiceImpl.queryEffective();
            return shopPermissionBos.stream().map(ShopPermissionBO::getId).collect(Collectors.toList());
        } else if (FrontendTypeEnum.TENANT.getCode().equals(module)) {
            List<TenantPermissionBO> tenantPermissionBos = getBean().queryAll();
            return tenantPermissionBos.stream().map(TenantPermissionBO::getId).collect(Collectors.toList());
        } else if (FrontendTypeEnum.CUSTOMER_SERVICE.getCode().equals(module)) {
            List<CsPermissionBO> csPermissionBos = csPermissionServiceImpl.queryEffective();
            return csPermissionBos.stream().map(CsPermissionBO::getId).collect(Collectors.toList());
        }  else if (FrontendTypeEnum.CP.getCode().equals(module)) {
            List<CpPermissionBO> cpPermissionBos = cpPermissionServiceImpl.queryEffective();
            return cpPermissionBos.stream().map(CpPermissionBO::getId).collect(Collectors.toList());
        } else {
            return Collections3.emptyList();
        }
    }

    private static ITenantPermissionService getBean() {
        return SpringBeanUtil.getBean(ITenantPermissionService.class);
    }
}
